/*
**网关本地串口模块，功能：配置串口，读写串口等 modbus-RTU协议
**By hkm
*/


#include	<stdio.h>      
#include	<stdlib.h>    
#include	<unistd.h>    
#include	<sys/types.h>  
#include	<sys/stat.h>   
#include	<fcntl.h>      
#include	<errno.h>     
#include	<string.h>
#include	<termios.h>  
#include    <sys/select.h>

#include "uart.h"

#define COM_BAUDDEF			(115200)
#define	COM_DABITSDEF		(8)
#define COM_STBITSDEF		(1)
#define COM_PARITYDEF		('N')
#define SERIAL_MAX_DATA      512
#define	 UART_DEFAULT_TIMEOUT		500		//默认串口超时时间




/**-----------------------------------------------------------------------------------------------
* 函数名称 :	int UartInit(UartInfo *uart, char *configs)
* 功能描述 :	设置串口参数
* 入口参数 :	fd -已打开的串口文件描述符
				configs-参数内容
* 编辑作者 :	xzhw
* 返回值       ： 成功返回0；失败返回-1
* 备  注	   ： configs ="115200,8,1,N" 115200代表波特率，8数据位，1停止位，N无校验
------------------------------------------------------------------------------------------------*/

int UartInit(int fd, char *configs)
{
	int uBaudRate, databits, stopbits;
	char parity;
	char temp[32];
	char *p1 = NULL, *p2 = NULL;
	int n = 0;
	unsigned int flag = 0;
	unsigned short Speed;
	int stats;
	struct termios options;

	if(fd < 0 || NULL == configs){
        return -1;
    }
    
	/* clear struct for new port settings */
	bzero(&options, sizeof (struct termios));

	//波特率
	p1 = configs;
	p2 = strchr(p1, ',');
	n = p2 - p1;
	if (n) {
		strncpy(temp, p1, n);
		temp[n] = '\0';
		uBaudRate = atoi(temp);
	}
	else
		uBaudRate = COM_BAUDDEF;

	//数据位
	p1 = strchr(p2 + 1, ',');
	n = p1 - (p2 + 1);
	if (n) {
		strncpy(temp, p2 + 1, n);
		temp[n] = '\0';
		databits = atoi(temp);
	}
	else
		databits = COM_DABITSDEF;

	// 停止位
	p2 = strchr(p1 + 1, ',');
	n = p2 - (p1 + 1);
	if (n) {
		strncpy(temp, p1 + 1, n);
		temp[n] = '\0';
		stopbits = atoi(temp);
	}
	else
		stopbits = COM_STBITSDEF;

	//校验位
	if (p2 + 1 != NULL) {
		strcpy(temp, p2 + 1);
		parity = temp[0];
	}
	else {
		parity = COM_PARITYDEF;
	}

	//设置波特率
	switch (uBaudRate) {
	case 110:
		Speed = B110;
		break;

	case 300:
		Speed = B300;
		break;

	case 600:
		Speed = B600;
		break;

	case 1200:
		Speed = B1200;
		break;

	case 2400:
		Speed = B2400;
		break;

	case 4800:
		Speed = B4800;
		break;

	case 9600:
		Speed = B9600;
		break;

	case 19200:
		Speed = B19200;
		break;

	case 38400:
		Speed = B38400;
		break;

	case 57600:
		Speed = B57600;
		break;

	case 115200:
		Speed = B115200;
		break;

	case 230400:
		Speed = B230400;
		break;

	case 460800:
		Speed = B460800;
		break;

	case 921600:
		Speed = B921600;
		break;

	default:
		fprintf(stderr, "Unsupported data size\n");
		return -1;
	}

	flag |= Speed;

	//设置数据位
	switch (databits) {
	case 5:
		flag |= CS5;
		break;

	case 6:
		flag |= CS6;
		break;

	case 7:
		flag |= CS7;
		break;

	case 8:
		flag |= CS8;
		break;

	default:
		fprintf(stderr, "Unsupported data size\n");
		return -1;

	}

	//设置停止位
	switch (stopbits) {
	case 1:
		break;

	case 2:
		flag |= CSTOPB;
		break;

	default:
		fprintf(stderr, "Unsupported stop bits\n");
		return -1;

	}

	//设置奇偶校验位
	switch (parity) {
	case 'n':
	case 'N':	//无校验
		options.c_iflag = IGNPAR;
		break;

	case 'e':
	case 'E':	//偶校验
		flag |= PARENB;
		options.c_iflag = 0;
		break;

	case 'o':
	case 'O':	//奇校验
		flag |= PARENB | PARODD;
		options.c_iflag = 0;
		break;

	case 's':
	case 'S':
		flag |= PARENB | CMSPAR;
		options.c_iflag = 0;
		break;

	case 'm':
	case 'M':
		flag |= PARENB | PARODD | CMSPAR;
		options.c_iflag = 0;
		break;

	default:
		fprintf(stderr, "Unsupported parity\n");
		return -1;

	}

	options.c_cflag = flag | CREAD | CLOCAL;
	options.c_oflag = 0;
	options.c_lflag = 0;
	options.c_cc[VINTR] = 0;
	options.c_cc[VQUIT] = 0;
	options.c_cc[VERASE] = 0;
	options.c_cc[VKILL] = 0;
	options.c_cc[VEOF] = 4;
	// 100MS 串口等待接收(2S)
	options.c_cc[VTIME] = 0; 
	options.c_cc[VMIN] = 0;
	options.c_cc[VSWTC] = 0;
	options.c_cc[VSTART] = 0;
	options.c_cc[VSTOP] = 0;
	options.c_cc[VSUSP] = 0;
	options.c_cc[VEOL] = 0;
	options.c_cc[VREPRINT] = 0;
	options.c_cc[VDISCARD] = 0;
	options.c_cc[VWERASE] = 0;
	options.c_cc[VLNEXT] = 0;
	options.c_cc[VEOL2] = 0;

	//刷新输入输出缓冲
	tcflush(fd, TCIOFLUSH);

	//把设置真正写到串口中去
	stats = tcsetattr(fd, TCSANOW, &options);

	if (stats != 0) {
		perror("tcsetattr fd1");
		return -1;
	}


	return 0;
}




/**@fn static int UartRecv(int fd, unsigned char *data, unsigned int timerout)
 * @brief UART recv
 * @brief 2019/09/18 hkm
 * @param [in] fd  串口文件描述符
 * @param [out]  data 接收的数据
 * @param [in]  timeout 超时时间 ms
 * @return 成功返回接收到的字节个数，失败返回-1
 */
int UartRecv(int fd, unsigned char *data, unsigned int timerout)
{
    int maxfd = 0;
    struct timeval tv = {0};
    fd_set rd_fd;
    int ret = 0;
    int len = 0;

    tv.tv_sec = (timerout / 1000);
    tv.tv_usec = (timerout % 1000) * 1000;

    maxfd = fd + 1;

    FD_ZERO(&rd_fd);
    FD_SET(fd, &rd_fd);
    ret = select(maxfd, &rd_fd, NULL, NULL, &tv);
    if(ret <= 0){
        return -1;
    }
    ret = read(fd, data, SERIAL_MAX_DATA);

    return ret;
}


/**@fn static int UartSend(int fd, unsigned char *data, int len)
 * @brief UART send 
 * @brief 2019/09/18 hkm
 * @param [in] fd  串口文件描述符
 * @param [in]  data 发送的数据
 * @param [in]  len 发送长度
 * @return 成功返回发出的字节个数，失败返回-1
 */
int UartSend(int fd, unsigned char *data, int len)
{
	if(fd < 0 || (NULL == data) || (len <= 0)){
		return -1;
	}

	int maxfd = 0;
    struct timeval tv = {0};
    fd_set wr_fd;
    int ret = 0;

    tv.tv_sec = 0;
	tv.tv_usec = 20000;	

	maxfd = fd + 1;

    FD_ZERO(&wr_fd);
    FD_SET(fd, &wr_fd);
    ret = select(maxfd, NULL, &wr_fd, NULL, &tv);
    if(ret <= 0){
		printf("can not write serial \n");
		return -1;
    }

	return write(fd, data, len);
}




